package com.ugrow.ugrowcommunity.util;

import android.annotation.SuppressLint;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

import com.google.gson.Gson;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.FormBody;
import okhttp3.HttpUrl;
import okhttp3.Interceptor;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import static java.lang.String.valueOf;

public class HttpUtil {
    private static final String TAG = "HttpUtil";
    private static final Executor netThread = Executors.newCachedThreadPool();
    private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");

    public static final OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .connectTimeout(10, TimeUnit.SECONDS)
            .addInterceptor(new LoggingInterceptor())
            .build();
    private static final int SUCCESS_CODE = 1;
    private static final int FAILED_CODE = 2;

    private static class LoggingInterceptor implements Interceptor {

        @Override
        public Response intercept(Chain chain) throws IOException {
            final Request request = chain.request();
            long t1 = System.nanoTime();
            Log.d(TAG, "okhttp3 request " + request.url() + " on " + chain.connection() + request.headers());
            Response response = chain.proceed(request);
            long t2 = System.nanoTime();
            Log.d(TAG, "Received response " + response.request().url() + " in " + (t2 - t1) / 1e6 + "ms " + response.code());
            return response;
        }
    }

    public static class Result {
        public boolean success;
        public int code;
        public String content;

        public Result(boolean success, int code, String content) {
            this.success = success;
            this.code = code;
            this.content = content;
        }

        @Override
        public String toString() {
            return "Result{" +
                    "success=" + success +
                    ", code=" + code +
                    ", content='" + content + '\'' +
                    '}';
        }
    }

    public enum ContentType {
        JSON, FROM, IMAGE
    }

    public interface CallBack {
        void success(Result result);

        void failed(IOException e);
    }

    private static CallBack callback;
    @SuppressLint("HandlerLeak")
    private static Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case SUCCESS_CODE:
                    callback.success((Result) msg.obj);
                    break;
                case FAILED_CODE:
                    callback.failed((IOException) msg.obj);
                    break;
            }
        }
    };

    public static void httpGet(String url,Map<String, String> map,CallBack _callback){
        netThread.execute(() -> {
            HttpUrl.Builder urlBuilder = Objects.requireNonNull(HttpUrl.parse(url)).newBuilder();
            for (String key : map.keySet()) {
                urlBuilder.addQueryParameter(key, map.get(key));
            }
            Request request = new Request.Builder().url(urlBuilder.build()).build();
            Result result;
            callback = _callback;
            try {
                Response response;
                response = okHttpClient.newCall(request).execute();
                Log.d(TAG, "httpPost: " + response.isSuccessful());
                int code;
                String body = Objects.requireNonNull(response.body()).string();
                try {
                    JSONObject jsonObject = new JSONObject(body);
                    code = jsonObject.getInt("code");
                } catch (JSONException e) {
                    e.printStackTrace();
                    code = 0;
                }

                result = new Result(response.isSuccessful(), code, response.body() != null ? body : "unknown");
                Message msg = Message.obtain();
                msg.what = SUCCESS_CODE;
                msg.obj = result;
                mHandler.sendMessage(msg);

            } catch (IOException e) {
                Message msg = Message.obtain();
                msg.what = FAILED_CODE;
                msg.obj = e;
                mHandler.sendMessage(msg);
            }
        });
    }




    public static void httpPost(String url, HashMap<String, Object> map, ContentType type, CallBack _callBack) {
        netThread.execute(() -> {
            Request request;
            if (type == ContentType.JSON) {
                String json = new Gson().toJson(map);
                RequestBody body = RequestBody.create(JSON, json);
                request = new Request.Builder()
                        .url(url)
                        .post(body)
                        .build();
            } else if (type == ContentType.FROM) {
                FormBody.Builder builder = new FormBody.Builder();
                for (Map.Entry<String, Object> entry : map.entrySet()) {
                    builder.add(entry.getKey(), (String) entry.getValue());
                }

                FormBody formBody = builder.build();
                request = new Request.Builder()
                        .post(formBody)
                        .url(url)
                        .build();
            } else if (type == ContentType.IMAGE) {
                MultipartBody.Builder requestBody = new MultipartBody.Builder().setType(MultipartBody.FORM);

                if (map != null) {
                    for (Map.Entry<String, Object> entry : map.entrySet()) {
                        if (entry.getValue() instanceof File) {
                            RequestBody body = RequestBody.create(MediaType.parse("image/*"), (File) entry.getValue());
                            String filename = ((File) entry.getValue()).getName();
                            requestBody.addFormDataPart(entry.getKey(), filename, body);

                        }
                        requestBody.addFormDataPart(valueOf(entry.getKey()), valueOf(entry.getValue()));
                    }
                }
                request = new Request.Builder().url(url).post(requestBody.build()).build();
            } else return;
            Result result;
            callback = _callBack;
            try {
                Response response;
                response = okHttpClient.newCall(request).execute();
                Log.d(TAG, "httpPost: " + response.isSuccessful());
                int code;
                String body = Objects.requireNonNull(response.body()).string();
                try {
                    JSONObject jsonObject = new JSONObject(body);
                    code = jsonObject.getInt("code");
                } catch (JSONException e) {
                    e.printStackTrace();
                    code = 0;
                }

                result = new Result(response.isSuccessful(), code, response.body() != null ? body : "unknown");
                Message msg = Message.obtain();
                msg.what = SUCCESS_CODE;
                msg.obj = result;
                mHandler.sendMessage(msg);

            } catch (IOException e) {
                Message msg = Message.obtain();
                msg.what = FAILED_CODE;
                msg.obj = e;
                mHandler.sendMessage(msg);
            }
        });
    }


    public static class Post {

        public Post(Result r) {
            this.r = r;
        }

        private Result r;
        private Request.Builder request = new Request.Builder();
        private HashMap<String, String> map = new HashMap<>();
        private Call call = null;


        public Post putUrl(String url) {
            request.url(url);
            return this;
        }

        public Post putParam(HashMap<String, String> _map) {
            map = _map;
            return this;
        }

        public Post build() {
            final StringBuilder string = new StringBuilder(256);
            final FormBody.Builder formBody = new FormBody.Builder();
            for (Map.Entry<String, String> entry : map.entrySet()) {
                formBody.add(entry.getKey(), entry.getValue());
                string.append('[').append(entry.getKey()).append('=').append(entry.getValue()).append(',');
            }
            string.append(']');
            Log.d(TAG, "okhttp request:" + string);
            request.post(formBody.build());
            call = okHttpClient.newCall(request.build());
            return this;
        }

        public void execute() {
            if (call != null) {
                try {
                    Response execute = call.execute();
                    r.success = execute.isSuccessful();
                    try {
                        JSONObject jsonObject = new JSONObject(execute.body().string());
                        r.code = jsonObject.getInt("code");
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }
                    r.content = execute.body() != null ? execute.body().string() : "unsuccessful";

                } catch (IOException e) {
                    r.success = false;
                    r.content = e.getMessage() != null ? e.getMessage() : "unknown";
                }
            }
        }
    }
}

